package moon.excel.reader.impl;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

import moon.excel.ExcelWraperException;
import moon.excel.IRecordInterceptor;
import moon.excel.reader.IExcelReader;
import moon.excel.util.ExcelUtil;
import moon.util.DateUtils;
import moon.util.StringUtils;

/**
 * 基于事件读取xlsx格式excel
 * 
 * @author Sunset
 *
 */
public class NewExcelEventReader extends DefaultHandler implements IExcelReader {

	private SharedStringsTable sst;

	private XSSFReader reader;

	private String lastContents;

	private Object[] tempRowdata;

	private IRecordInterceptor<Object[]> recordInterceptor = null;

	private int minColumn;

	private int rowIndex = 0;

	private int columnIndex = 0;

	private int rowBeginIndex = 0;

	private int columnBeginIndex = 0;

	private Class<?>[] ColumnClasss;

	private int[] rowIndexs;

	private String cellType;

	private XMLReader parser;

	public NewExcelEventReader(InputStream is) throws Exception {
		OPCPackage pkg = OPCPackage.open(is);
		reader = new XSSFReader(pkg);
		this.sst = reader.getSharedStringsTable();
		parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
		parser.setContentHandler(this);
	}

	/**
	 * See org.xml.sax.helpers.DefaultHandler javadocs
	 */

	public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
		lastContents = "";
		if (name.equals("row")) {
			rowIndex = Integer.parseInt(attributes.getValue("r")) - 1;
		} else if (name.equals("c")) {
			cellType = "";
			String r = attributes.getValue("r");
			columnIndex = ExcelUtil.getColumnIndex(r.replaceAll("[0-9]", "")) - 1;
			cellType = attributes.getValue("t");
		}
	}

	public void endElement(String uri, String localName, String name) throws SAXException {
		if (name.equals("row")) {
			handleNewRow();
		} else if (name.equals("v") || name.equals("t")) {// cell数据
			Object r = lastContents;
			if (StringUtils.isNotBlank(cellType)) {
				if (cellType.equals("s")) {
					int idx = Integer.parseInt(lastContents);
					r = new XSSFRichTextString(sst.getEntryAt(idx)).toString();
				} else if (cellType.equals("b")) {
					if (lastContents.equals("0")) {
						r = Boolean.FALSE;
					} else if (lastContents.equals("1")) {
						r = Boolean.TRUE;
					}
				} else if (cellType.equals("n")) {
					r = Double.parseDouble(lastContents);
				} else if (cellType.equals("d")) {
					if (lastContents.matches("\\d+(\\.\\d+)?")) {
						r = DateUtil.getJavaDate(Double.parseDouble(lastContents));
					} else {
						r = DateUtils.parseDate(lastContents);
					}
				}
			}
			if (columnIndex >= columnBeginIndex && columnIndex < minColumn) {
				// 每一列
				if (ColumnClasss != null && ColumnClasss.length == minColumn && ColumnClasss[columnIndex] != null) {
					try {
						if (!ColumnClasss[columnIndex].isAssignableFrom(r.getClass())) {
							tempRowdata[columnIndex] = ExcelUtil.convert(r, ColumnClasss[columnIndex]);
						} else {
							tempRowdata[columnIndex] = r;
						}
					} catch (Exception e) {
						e.printStackTrace();
						tempRowdata[columnIndex] = r;
					}
				} else {
					tempRowdata[columnIndex] = r;
				}
			}
		}
	}

	@Override
	public void endDocument() throws SAXException {
	}

	private void handleNewRow() {
		if (rowIndexs != null) {
			if (ArrayUtils.contains(rowIndexs, rowIndex)) {
				recordInterceptor.handle(tempRowdata, rowIndex + 1);
				rowIndexs = ArrayUtils.removeElement(rowIndexs, rowIndex);
			}
			if (rowIndexs.length == 0) {
				throw new ExcelWraperException("搜索完毕");
			}
		} else {
			if (rowIndex >= rowBeginIndex) {
				recordInterceptor.handle(tempRowdata, rowIndex + 1);
			}
		}
	}

	public void characters(char[] ch, int start, int length) throws SAXException {
		lastContents += new String(ch, start, length);
	}

	@Override
	public void readSheet(Integer sheetIndex, int rowBeginIndex, int columnBeginIndex, int columnEndIndex, Class<?>[] classs, IRecordInterceptor<Object[]> interceptor) {
		reset(sheetIndex, rowBeginIndex, columnBeginIndex, columnEndIndex, null, classs, interceptor);
	}

	@Override
	public void readSheet(Integer sheetIndex, int columnBeginIndex, int columnEndIndex, int[] rowIndexs, Class<?>[] classs, IRecordInterceptor<Object[]> interceptor) {
		reset(sheetIndex, 0, columnBeginIndex, columnEndIndex, rowIndexs, classs, interceptor);
	}

	@Override
	public Object[] readRow(Integer sheetIndex, int rowIndex, int columnBeginIndex, int columnEndIndex, Class<?>[] classs) throws UnsupportedOperationException {
		final List<Object[]> list = new ArrayList<Object[]>();
		reset(sheetIndex, 0, columnBeginIndex, columnEndIndex, new int[] { rowIndex }, classs, new IRecordInterceptor<Object[]>() {

			@Override
			public void handle(Object[] t, int rowIndex) {
				list.add(t);
			}

		});
		return list.isEmpty() ? null : list.get(0);
	}

	private void reset(Integer sheetIndex, int rowBeginIndex, int columnBeginIndex, int columnEndIndex, int[] rowIndexs, Class<?>[] classs, IRecordInterceptor<Object[]> interceptor) {
		try {
			if (interceptor == null) {
				throw new RuntimeException("记录拦截器不能为空");
			}
			this.rowBeginIndex = rowBeginIndex;
			this.columnBeginIndex = columnBeginIndex;
			this.recordInterceptor = interceptor;
			this.ColumnClasss = classs;
			this.recordInterceptor = interceptor;
			this.minColumn = columnEndIndex - columnBeginIndex + 1;
			this.rowIndexs = rowIndexs;
			this.rowIndex = 0;
			this.columnIndex = 0;
			tempRowdata = new Object[minColumn];
			Iterator<InputStream> sheets = reader.getSheetsData();
			int i = 0;
			while (sheets.hasNext()) {
				InputStream sheet = sheets.next();
				if (sheetIndex != null && sheetIndex >= 0 && !sheetIndex.equals(i)) {
					i++;
					continue;
				}
				InputSource sheetSource = new InputSource(sheet);
				try {
					parser.parse(sheetSource);
				} catch (ExcelWraperException e) {
					if (!e.getMessage().equals("搜索完毕")) {
						e.printStackTrace();
					}
				}
				sheet.close();
				i++;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
